
/// 下拉菜单,包含以下功能
/// 1.可以由定义每个item项目的样式,由外面创建好传进来
/// 2.通过controller来控制控件的弹出或关闭
/// 3.选择了菜单项后通过delegate传递到外部


import 'package:flutter/material.dart';

class WFDropdown extends StatefulWidget {

  Widget child;
  List<Widget> listItems;
  double listHeight;
  Decoration? decoration;

  DropdownController? controller;
  DropdownDelegate? delegate;


  WFDropdown({Key? key,
    required this.child,
    required this.listItems,
    required this.listHeight,
    this.decoration,
    this.controller,
    this.delegate,}) : super(key: key);

  @override
  _WFDropdownState createState() => _WFDropdownState();
}

class _WFDropdownState extends State<WFDropdown> with TickerProviderStateMixin{
  static final Animatable<double> _easeInTween =
  CurveTween(curve: Curves.easeIn);
  late AnimationController _controller;
  late Offset _offset;
  late double _height;
  OverlayEntry? _entry;
  OverlayEntry? _entry2;
  OverlayEntry? _barrierOverlay;
  late Animation<double> _heightFactor;
  final _layerLink = LayerLink();
  final int _duration = 150;
  late bool _isExpanded=false;


  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: _duration),
    );
    _heightFactor = _controller.drive(_easeInTween);
    widget.controller?._showDropList = (){
      // _isExpanded = true;
      // setState(() {});
      _showOverlay();
    };
    widget.controller?._hideDropList = (){
      hideOverlay();
    };
    widget.controller?._updateItems = (List<Widget> items){
      widget.listItems = items;
      hideOverlay();
      _showOverlay();
      setState(() {});
    };
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: (){
        print("taped");
        _isExpanded = !_isExpanded;
        _isExpanded?_showOverlay():hideOverlay();
        // _showOverlay();
      },
      child: CompositedTransformTarget(
          link: _layerLink,
          child: widget.child
      ),
    );
  }

  _showOverlay(){
    FocusScope.of(context).requestFocus(FocusNode());
    _controller.forward();
    _isExpanded = true;
    widget.controller?.setShowing=_isExpanded;
    final overlay = Overlay.of(context);
    final renderBox = context.findRenderObject() as RenderBox;
    final size = renderBox.size;
    _offset = renderBox.localToGlobal(Offset.zero);
    double posFromTop = _offset.dy;
    double posFromBot = MediaQuery.of(context).size.height - posFromTop;

    // double dropdownListHeight = _height +
    // 	 (widget.enableSearch ? _searchWidgetHeight : 0) +
    // 	 widget.listSpace;
    double dropdownListHeight = 0;
    // double ht = dropdownListHeight + 0;
    double ht = widget.listHeight;

    bool up = _offset.dy + size.height + widget.listHeight >  MediaQuery.of(context).size.height;
    // up = !up;
    print('isup:$up');


    _entry = OverlayEntry(
      builder: (context) => Positioned(
          width: size.width,
          child: CompositedTransformFollower(
            // targetAnchor: Alignment.topCenter,
            // followerAnchor: Alignment.bottomCenter,

            // targetAnchor: Alignment.topCenter,
            // followerAnchor: Alignment.topCenter,

            // targetAnchor: posFromBot < ht
            // 	 ? Alignment.bottomCenter
            // 	 : Alignment.topCenter,
            // followerAnchor: posFromBot < ht
            // 	 ? Alignment.bottomCenter
            // 	 : Alignment.topCenter,

              targetAnchor: up
                  ? Alignment.topCenter
                  : Alignment.bottomCenter,
              followerAnchor: up
                  ? Alignment.bottomCenter
                  : Alignment.topCenter,

              link: _layerLink,
              showWhenUnlinked: false,
              offset: Offset(
                  0,0
                // posFromBot < ht
                // 	 ? htPos - widget.listSpace
                // 	 : htPos + widget.listSpace,
              ),
              child: AnimatedBuilder(
                animation: _controller.view,
                builder: buildOverlay,
              ))),
    );
    overlay?.insert(_entry!);
    // if (alreadyHaveEntry==false) {
    //   alreadyHaveEntry=true;
    //   overlay?.insert(_entry!);
    // } else
    //   {
    //     setState(() {});
    //   }
  }

  Widget buildOverlay(context, child) {
    return ClipRect(
      child: Align(
        heightFactor: _heightFactor.value,
        child: Material(
          color: Colors.transparent,
          child: Padding(
            padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 4),
            child: Container(
              decoration: widget.decoration,
              // decoration: const BoxDecoration(
              //   // color: Colors.cyan,
              //   borderRadius:
              //   BorderRadius.all(Radius.circular(8)),
              //   // boxShadow: const [
              //   // 	BoxShadow(
              //   // 		color: Colors.grey,
              //   // 		blurRadius: 5,
              //   // 	),
              //   // ],
              // ),
              child: Container(
                height: widget.listHeight,
                decoration: widget.decoration,
                child: ListView.builder(
                    padding: EdgeInsets.zero,
                    itemCount: widget.listItems.length,
                    itemBuilder: (_ctx,_idx){
                      return widget.delegate==null
                       ?widget.listItems[_idx]
                      :GestureDetector(
                        onTap: (){
                          widget.delegate?.onClickedItem(_idx);
                        },
                        child:widget.listItems[_idx],
                      );

                    }),
              ),
            ),
          ),
        ),
      ),
    );
  }

  void hideOverlay() {
    // if (!_isScrollPadding) {}
    _controller.reverse().then<void>((void value) {
      if (_entry != null && _entry!.mounted) {
        _entry?.remove();
        _entry = null;
      }
      if (_entry2 != null && _entry2!.mounted) {
        _entry2?.remove();
        _entry2 = null;
      }

      if (_barrierOverlay != null && _barrierOverlay!.mounted) {
        _barrierOverlay?.remove();
        _barrierOverlay = null;
        // _isOutsideClickOverlay = false;
      }
      // _isScrollPadding = false;
      _isExpanded = false;
      widget.controller?.setShowing=_isExpanded;
    });
  }
}


class DropdownController extends ValueNotifier<bool>{
  Function? _showDropList;
  Function? _hideDropList;
  Function? _updateItems;

  // int? _currIndex;
  bool _isShowing=false;

  get isShowing => _isShowing;

  // get currIndex => _currIndex;
  // set setIndex(int newIndex) {
  //   _currIndex = newIndex;
  // }

  set setShowing(bool flag) {
    _isShowing = flag;
  }

  DropdownController({bool value=false}) : super(value);

  showDropList() {
    _showDropList?.call();
  }

  hideDropList() {
    _hideDropList?.call();
  }

  updateItems(List<Widget> items){
    _updateItems?.call(items);
  }


}

abstract class DropdownDelegate{
  void onClickedItem(int idx);
}
